﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.IO;

namespace Krile.Kernel.Control.Surface.MessageObjects
{
    public class Image : MessageObject
    {
        System.Drawing.Image cache
        {
            get { return _cache; }
            set
            {
                if(animate != null)
                {
                    ImageAnimator.StopAnimate(_cache, animate);
                    animate = null;
                }
                _cache = value;
                try
                {
                    if (ImageAnimator.CanAnimate(_cache))
                    {
                        animate = new EventHandler(FrameUpdated);
                        ImageAnimator.Animate(_cache, animate);
                    }
                }
                catch (ArgumentException) { }
            }
        }

        EventHandler animate = null;
        private void FrameUpdated(object sender, EventArgs e)
        {
            if (activated)
            {
                if (ParentForm != null)
                    ParentForm.RefreshTLWeak(false);
            }
        }

        System.Drawing.Image _cache = null;

        public Image(Uri uri)
        {
            ImageUri = uri;
        }

        Uri _imgUri;
        public Uri ImageUri
        {
            get { return _imgUri; }
            set
            {
                _imgUri = value;
            }
        }

        public void RefreshImage()
        {
            Release();
            cache = Properties.Resources.loading;
            Bridge.ImageManager.GetImageCallback(ImageUri, false, new Krile.Kernel.Bridges.GetImageCallbackDelegate(ImageDLCompleted));
        }

        public void ImageDLCompleted(Uri uri, System.Drawing.Image img)
        {
            Release();
            if (ImageUri == uri && img != null)
                cache = img;
            else
            {
                cache = Properties.Resources.error;
                if (img != null)
                    img.Dispose();
                img = null;
            }
            if (ParentForm != null)
                ParentForm.RefreshTL(true);
        }

        /// <summary>
        /// Use static size prop
        /// </summary>
        public bool UseStaticSize { get; set; }

        /// <summary>
        /// Static size for rendering image
        /// </summary>
        public Size StaticSize { get; set; }

        /// <summary>
        /// Ignoring system maximum
        /// </summary>
        public bool IgnoreSystemMaximum { get; set; }

        /// <summary>
        /// No line-break before and after rendering
        /// </summary>
        public bool Inline { get; set; }

        private bool tempIgMax = false;

        Size drawnSize = new Size();
        bool newLineStart = false;
        public override void Composite(Compositor compz)
        {
            drawnRegion = null;
            newLineStart = false;
            if (!Inline)
            {
                compz.MoveNewLine();
                newLineStart = true;
            }
            if (UseStaticSize)
            {
                if (Inline && compz.ClientWidth - compz.CurrentXPosition < StaticSize.Width)
                {
                    compz.MoveNewLine();
                    newLineStart = true;
                }
                compz.SetCurrentLineHeight(StaticSize.Height);
                compz.CurrentXPosition += StaticSize.Width;
                drawnSize = StaticSize;
                if (Inline && compz.CurrentXPosition == compz.ClientWidth)
                    compz.MoveNewLine();
            }
            else
            {
                if (Inline)
                {
                    compz.MoveNewLine();
                    newLineStart = true;
                }
                if (cache == null)
                    RefreshImage();
                if (cache == null)
                    return;
                int capable = compz.ClientWidth - compz.CurrentXPosition;
                double zoom = 1.0;
                if (capable < cache.Width)
                    zoom = (double)capable / cache.Width;
                if (!tempIgMax && !IgnoreSystemMaximum)
                {
                    if (cache.Height * zoom > Bridge.Config.DisplayConfig.ImageDefaultMaxSize.Height)
                        zoom = (double)Bridge.Config.DisplayConfig.ImageDefaultMaxSize.Height / cache.Height;
                    if (cache.Width * zoom > Bridge.Config.DisplayConfig.ImageDefaultMaxSize.Width)
                        zoom = (double)Bridge.Config.DisplayConfig.ImageDefaultMaxSize.Width / cache.Width;
                }
                compz.SetCurrentLineHeight((int)(cache.Height * zoom));
                compz.CurrentXPosition += (int)(cache.Width * zoom);
                drawnSize = new Size(
                    (int)(cache.Width * zoom),
                    (int)(cache.Height * zoom));
                if (Inline && capable <= cache.Width)
                    compz.MoveNewLine();
            }
            if (!Inline)
                compz.MoveNewLine();
        }

        public override string HelptipText
        {
            get
            {
                if (tempIgMax)
                    return Lang.MessageObjects.ImageHelptipText_Maximized;
                else
                    return Lang.MessageObjects.ImageHelptipText;
            }
        }

        Rectangle? drawnRegion = null;
        public override void Draw(Graphics g, CompositeDescriptor desc)
        {
            if (animate != null)
                ImageAnimator.UpdateFrames(_cache);
            Rectangle target = new Rectangle(desc.LeftTop, drawnSize);
            if (cache == null)
                return;
            if (newLineStart)
                target.Y += desc.Heights[0];
            else
                target.X += desc.StartXPos;
            g.DrawImage(cache, target);
            drawnRegion = target;
        }

        public override bool HitTest(Point position)
        {
            if (drawnRegion == null || !drawnRegion.HasValue)
                return false;
            else
                return drawnRegion.Value.HitTest(position);
        }

        volatile bool activated = false;
        public override void Activate()
        {
            activated = true;
        }

        public override void Release()
        {
            activated = false;
            if (cache != null)
            {
                cache.Dispose();
                cache = null;
                drawnRegion = null;
                tempIgMax = false;
            }
        }

        public override void OnMouseEnter(object sender, ChainMouseEventArgs e)
        {
            if (ParentForm != null)
                ParentForm.SetCursor(Cursors.Hand);
        }

        public override void OnMouseLeave(object sender, ChainMouseEventArgs e)
        {
            if (ParentForm != null)
                ParentForm.SetCursor(Cursors.Default);
        }

        public override void OnMouseClick(object sender, ChainMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                tempIgMax = !tempIgMax;
                if (ParentForm != null)
                {
                    ParentForm.RefreshTL(true);
                    ParentForm.EnsureVisible();
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                using (var sfd = new SaveFileDialog())
                {
                    sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
                    if(animate != null)
                        sfd.Filter = "animation GIF|*.gif";
                    else
                        sfd.Filter = "Jpeg|*.jpg|PNG|*.png|GIF|*.gif|Bitmap|*.bmp|Tiff|*.tiff";
                    if (sfd.ShowDialog() == DialogResult.OK)
                    {
                        var fn = sfd.FileName;
                        using (var img = new Bitmap(cache))
                        {
                            switch (Path.GetExtension(fn).ToLower())
                            {
                                case ".jpg":
                                case ".jpeg":
                                case ".jpe":
                                    img.Save(fn, ImageFormat.Jpeg);
                                    break;
                                case ".png":
                                    img.Save(fn, ImageFormat.Png);
                                    break;
                                case ".gif":
                                    img.Save(fn, ImageFormat.Gif);
                                    break;
                                case ".bmp":
                                case ".dib":
                                    img.Save(fn, ImageFormat.Bmp);
                                    break;
                                case ".tif":
                                case ".tiff":
                                    img.Save(fn, ImageFormat.Tiff);
                                    break;
                                default:
                                    img.Save(fn);
                                    break;
                            }
                        }
                    }
                }
            }
        }
    }
}
